package org.mymybatis.session;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.mymybatis.common.Const;
import org.mymybatis.datasource.UnPooledDataSource;
import org.mymybatis.io.Resources;
import org.mymybatis.mapping.MappedStatement;
import org.mymybatis.transaction.Transaction;
import org.mymybatis.transaction.jdbc.JDBCTransaction;
import org.mymybatis.transaction.managed.ManagedTransaction;

import javax.sql.DataSource;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: sh
 * @Version 1.0
 * @Description: SqlSessionFactory对象构建器
 */
public class SqlSessionFactoryBuilder {
    public SqlSessionFactoryBuilder() {
    }

    /**
     * 获取SqlSessionFactory对象
     * 该方法主要功能是：读取godbatis核心配置文件，并构建SqlSessionFactory对象
     *
     * @param inputStream
     * @return
     */

    public SqlSessionFactory build(InputStream inputStream) {
        SqlSessionFactory sqlSessionFactory = null;
        try {
            // 解析文件
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments");
            String defaultEnv = environmentsElt.attributeValue("default");
            Element environmentElt = (Element) document.selectSingleNode("/configuration/environments/environment[@id='" + defaultEnv + "']");
            Element dataSourceElt = environmentElt.element("dataSource");
            DataSource dataSource = getDataSource(dataSourceElt);
            // 解析配置文件，创建事务管理器对象
            Element transactionManagerElt = environmentElt.element("transactionManager");
            Transaction transaction = getTransactionManager(transactionManagerElt, dataSource);
            // 解析配置文件，获取所有的SQL映射对象
            Element mappers = (Element) document.selectSingleNode("/configuration/mappers");
            Map<String, MappedStatement> mappedStatements = getMappers(mappers);
            sqlSessionFactory = new SqlSessionFactory(transaction, mappedStatements);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
        return sqlSessionFactory;
    }

    private Map<String, MappedStatement> getMappers(Element mappers) {
        Map<String, MappedStatement> mappedStatements = null;
        try {
            mappedStatements = new HashMap<>();
            for (Element element : mappers.elements()) {
                String resourcePath = element.attributeValue("resource");
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(Resources.getResourceAsStream(resourcePath));
                Element mapper = (Element) document.selectSingleNode("/mapper");
                String namespace = mapper.attributeValue("namespace");  // 命名空间
                for (Element mapperSqlEle : mapper.elements()) {
                    String id = mapperSqlEle.attributeValue("id");
                    String sqlText = mapperSqlEle.getTextTrim();  // 就是具体的sql语句
                    String parameterType = mapperSqlEle.attributeValue("parameterType");  // 查询参数
                    String resultType = mapperSqlEle.attributeValue("resultType");  // 返回要封装的对象
                    String sqlType = mapperSqlEle.getName().toLowerCase(); // 看是增删改查那类标签
                    MappedStatement mappedStatement = new MappedStatement();
                    mappedStatement.setSqlId(id);
                    mappedStatement.setSql(sqlText);
                    mappedStatement.setResultType(resultType);
                    mappedStatement.setSqlType(sqlType);
                    mappedStatement.setParameterType(parameterType);
                    mappedStatements.put(namespace + "." + id, mappedStatement);
                }
            }
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
        return mappedStatements;
    }


    /**
     * 获取事务管理器
     *
     * @param transactionManagerElt
     * @param dataSource
     * @return
     */
    private Transaction getTransactionManager(Element transactionManagerElt, DataSource dataSource) {
        String transactionManagerType = transactionManagerElt.attributeValue("type").trim().toUpperCase();
        Transaction transaction = null;
        if (Const.TRANSACTION_MANAGER_JDBC.equals(transactionManagerType)) {
            transaction = new JDBCTransaction(dataSource, false);
        } else if (Const.TRANSACTION_MANAGER_MANAGED.equals(transactionManagerType)) {
            transaction = new ManagedTransaction();
        }
        return transaction;
    }

    private DataSource getDataSource(Element dataSourceElt) {
        Map<String, String> dataSourceMap = new HashMap<>();
        for (Element propertyElt : dataSourceElt.elements()) {
            String name = propertyElt.attributeValue("name");
            String value = propertyElt.attributeValue("value");
            dataSourceMap.put(name, value);
        }
        String dataSourceType = dataSourceElt.attributeValue("type").toUpperCase().trim();
        DataSource dataSource = null;
        if (Const.UN_POOLED_DATASOURCE.equals(dataSourceType)) {
            String driver = dataSourceMap.get("driver");
            String url = dataSourceMap.get("url");
            String username = dataSourceMap.get("username");
            String password = dataSourceMap.get("password");
            dataSource = new UnPooledDataSource(driver, url, username, password);
        }
        if (Const.POOLED_DATASOURCE.equals(dataSourceType)) {

        }
        if (Const.JNDI_DATASOURCE.equals(dataSourceType)) {

        }

        return dataSource;
    }

}

